//------------------------------------------------------------------------------
// Fichiers d'entete utilises
//------------------------------------------------------------------------------
#include <Settings.hpp>
#include <Math/Vector.hpp>
#include <Math/Matrix.hpp>
#include <Rendering/Camera.hpp>
#include <Rendering/OpenGL.hpp>
#include <Tools/Log.hpp>

namespace Rendering {

	//----------------------------------------------------------------------
	// Constructeur
	//----------------------------------------------------------------------
	Camera::Camera(float fov, float n, float f):
	IPointOfView(fov, n, f)
	{
		// Initialisation de la position de la cam�ra
		Position[0] = 0;
		Position[1] = 0;
		Position[2] = DEFAULT_CAMERA_POSITION_Z;
		Position[3] = 1;

		// Initialisation de la direction de la cam�ra
		Direction[0] = 0;
		Direction[1] = 0;
		Direction[2] = -1;
		Direction[3] = 0;

		// Initialisation du vecteur vertical de la cam�ra
		Up[0] = 0;
		Up[1] = 1;
		Up[2] = 0;
		Up[3] = 0;		
	}

	Camera::~Camera()
	{
	}

	//----------------------------------------------------------------------
	// Constructeur
	//----------------------------------------------------------------------
	void Camera::Print( )
	{
		Tools::Info("Camera::Position[%f,%f,%f,%f]\n",Position[0],Position[1],Position[2],Position[3]);
		Tools::Info("Camera::Direction[%f,%f,%f,%f]\n",Direction[0],Direction[1],Direction[2],Direction[3]);
		Tools::Info("Camera::Up[%f,%f,%f,%f]\n",Up[0],Up[1],Up[2],Up[3]);
	}

	//----------------------------------------------------------------------
	// D�place la cam�ra verticalement
	//----------------------------------------------------------------------
	void Camera::MoveVertical( float distance )
	{
		Vector::AddConstMul4( Position, Position, distance, Up);
	}

	//----------------------------------------------------------------------
	// D�place la cam�ra horizontalement
	//----------------------------------------------------------------------
	void Camera::MoveHorizontaly( float distance )
	{
		float right[4];
		Vector::Init4(right,0,0,0,0);
		Vector::Cross3( right, Direction, Up );
		Vector::AddConstMul4( Position, Position, distance, right);
	}

	//----------------------------------------------------------------------
	// D�place la cam�ra en profondeur
	//----------------------------------------------------------------------
	void Camera::MoveDeeply( float distance )
	{
		Vector::AddConstMul4( Position, Position, distance, Direction);
	}

	//----------------------------------------------------------------------
	// Tourne la cam�ra sur elle m�me selon l'axe et l'angle donn�s
	//----------------------------------------------------------------------
	void Camera::RotateCameraAxis( float* axis, float angle )
	{
		float rotationMatrix[16];
		float transformedDirection[4];
		//float transformedUp[4];
		Matrix::Rotate4(rotationMatrix, angle, axis[0], axis[1], axis[2] );
		Matrix::MulVec4(transformedDirection, rotationMatrix, Direction );
		//mat44_mul_vec(transformedUp, rotationMatrix, Up );
		Vector::Norm4(Direction,transformedDirection);
		//vec4_norm(Up,transformedUp);
	}	

	void Camera::RotateCamera( float angleX, float angleY )
	{		
		//RotateCameraAxis( camera, right, angleX );
		RotateCameraAxis( Up, angleX );

		float right[4];
		Vector::Init4(right,0,0,0,0);
		float direction[3];
		float up[3];
		float Right[3];
		Vector::Norm3(direction,Direction);
		Vector::Norm3(up,Up);
		Vector::Cross3( right, direction, Up );
		Vector::Norm3(Right,right);

		float axisZ[4];
		Vector::Init4(axisZ,0,0,1,0);
		//RotateCameraAxis( camera, axisZ, angleY);
		RotateCameraAxis( Right, -angleY);
	}
	//---------------------------------------------------------------------		
	void Camera::UpdateProjectionMatrix() {	
		// TODO define aspect
		Matrix::Perspective4(projectionMatrix, fieldOfView, 1.f, nearPlane, farPlane);
		//Matrix::LinearPerspective4(projectionMatrix, fieldOfView, 1.f, nearPlane, farPlane);
	}
	//---------------------------------------------------------------------
	void Camera::UpdateViewMatrix() {
		Vector::Vector3 target = {Position[0]+Direction[0], Position[1]+Direction[1], Position[2]+Direction[2]};
		Matrix::LookAt4(viewMatrix, Position, target, Up);	
		
		Matrix::Inverse4(matInverse,viewMatrix);
	}
	//---------------------------------------------------------------------
	
}
